home *** CD-ROM | disk | FTP | other *** search
/ MacTech 1 to 12 / MacTech-vol-1-12.toast / Source / MacTech® Magazine / Volume 03 - 1987 / 03.07 Jul 87 / bit map source / udrag.p < prev   
Encoding:
Text File  |  1987-04-24  |  12.5 KB  |  400 lines  |  [TEXT/MPS ]

  1. UNIT DragManager;
  2. {Version 1.0 Saturday, April 18, 1987 by Scott T. Boyd of
  3.  the MacHax™ Group.  Many thanks to Greg Marriott, also a
  4.  member of the MacHax Group. © 1987 by The MacHax Group, 
  5.  Bryan, TX.}
  6. {$D+}    {put in debug names}
  7. {$R+}    {range checking on}
  8. {$OV+} {overflow checking on}
  9. {$N+}    {pass routine names to linker, so they're not anonymous}
  10. INTERFACE
  11. USES {$LOAD pinterfaces.dump}        
  12.         MemTypes,QuickDraw,OsIntf,PasLibIntf,ToolIntf,
  13.         PackIntf,IntEnv,CursorCtl;
  14.  
  15. type 
  16.     shadowRecord = record
  17.         visible : boolean;
  18.         dx, dy : integer;
  19.         thePattern : Pattern;
  20.         copyMode : integer;
  21.     end;
  22.     dragHandle = ^dragPtr;
  23.     dragPtr = ^dragRecord;
  24.     dragRecord = record
  25.         shadowBits,                    {the shadow}
  26.         underShadowBits,            {what's under the shadow}
  27.         underBits,                     {bits obscured by picture}
  28.         pictureBits : BitMap;    {the picture}
  29.         shadowRegion,
  30.         thePictureRgn : RgnHandle;    {use this for masking}
  31.     end;
  32.     bitMapPtr = ^BitMap;
  33. var
  34.     shadowStuff : shadowRecord;
  35.  
  36. function InitDrag ( userOffscreenBits : bitMapPtr ) : boolean;
  37. function NewDraggable ( thePicture : PicHandle; 
  38.                                 userPicBits, userShadowBits : bitMapPtr;
  39.                                 var dragStuff : DragHandle ) : boolean;
  40. procedure DragItTo ( dragStuff: DragHandle; mousePt: point; 
  41.                                 centered : boolean );
  42. procedure DisposeDraggable ( dragStuff : DragHandle );
  43. procedure UpdateOffScreen (    dragStuff : DragHandle; 
  44.                                             Procedure drawProc );
  45. procedure CloseDrag ( disposeBitMap : boolean );
  46.  
  47. IMPLEMENTATION
  48. const
  49.     shadow_x = 4;
  50.     shadow_y = 6;
  51. var    
  52.     offScreenBits : BitMap;    {the picture}
  53.  
  54.     wMgrPort,
  55.     oldPort,
  56.     offPort : GrafPtr;
  57.     
  58.     updateRegion :     RgnHandle;
  59.     
  60.     lastRect,                        {this + dragRect => updateRegion}
  61.     otherUpdateRect,            {updateRect clipped to include only bits onscreen}
  62.     updateRect,                    {union of dragRect and lastRect}
  63.     dragRect,                        {size of the picture & centered over cursor}
  64.     tempBounds : Rect;        {used in creating bitmaps}
  65.     
  66.     mousePt,                        {used to position dragRect}
  67.     otherMousePt,                {used to see if cursor has moved}
  68.     testPt : Point;                {used to see if cursor has moved}
  69.     
  70.     synchCount : longint;    {wait for TickCount to change before drawing}
  71.  
  72. procedure Debugger; INLINE $A9FF;
  73.     
  74. function NewBitMap( var theBitMap : BitMap;  theRect : Rect ): ptr;
  75. begin
  76.     with theBitMap, theRect do
  77.     begin
  78.         rowBytes := ((right-left+15) DIV 16) * 2;
  79.         baseAddr := NewPtr(rowBytes * (bottom-top));
  80.         bounds := theRect;
  81.         if MemError <> noErr then NewBitMap := nil
  82.         else NewBitMap := baseAddr;
  83.     end;
  84. end; {NewBitMap}
  85.  
  86. function InitDrag ( userOffscreenBits : bitMapPtr ) : boolean;
  87. begin
  88.     InitDrag := false;
  89. {do all the work in the wMgrPort}
  90.     GetPort( oldPort );
  91.     GetWMgrPort( wMgrPort );
  92. {now make an offscreen bitmap to hold the whole screen}
  93. {if one already exists, ignore what they pass in}
  94.     if userOffScreenBits <> nil
  95.         then offScreenBits := BitMap(userOffScreenBits^)
  96.         else if NewBitMap( offScreenBits, screenBits.bounds ) = nil
  97.             then exit( InitDrag );
  98.  
  99. {make the grafport to play with.  this way I can really trash up
  100.  the grafport and not worry about saving and restoring the old one}
  101.     offPort := GrafPtr( NewPtr( sizeof( GrafPort ) ) );
  102.     if offPort = nil then 
  103.     begin
  104.         DisposPtr( offScreenBits.baseAddr );
  105.         exit( InitDrag );
  106.     end;
  107. {set up off screen port so we can draw in it}
  108.     OpenPort( offPort );
  109.     RectRgn( thePort^.visRgn, thePort^.clipRgn^^.rgnBBox );
  110.  
  111. {create the region to update with}
  112.     updateRegion := NewRgn;
  113.     if updateRegion = nil then 
  114.     begin
  115.         DisposPtr( offScreenBits.baseAddr );
  116.         ClosePort( offPort );
  117.         DisposPtr( Pointer( offPort ));
  118.         SetPort( oldPort );
  119.         exit( InitDrag );
  120.     end;
  121.     
  122. {set up the default shadow stuff}
  123.     with shadowStuff do
  124.     begin
  125.             visible := true;
  126.             dx := shadow_x;
  127.             dy := shadow_y;
  128.             thePattern := black;
  129.             copyMode := SrcXor;
  130.     end;
  131. {copy the screen}
  132.     CopyBits( screenBits, offScreenBits, screenBits.bounds, 
  133.             offScreenBits.bounds, srcCopy, nil );
  134.     InitDrag := true;
  135.     
  136.     SetPort( oldPort );
  137. end;{InitDrag}
  138.  
  139. function NewDraggable ( thePicture : PicHandle; 
  140.                                 userPicBits, userShadowBits: bitMapPtr;
  141.                                 var dragStuff : DragHandle ) : boolean;
  142.         procedure TestNil ( theThing : ptr );
  143.         begin
  144.             if theThing = nil then 
  145.             begin
  146.                 DisposeDraggable ( dragStuff );
  147.                 NewDraggable := false;
  148.                 SetPort( oldPort );
  149.                 exit ( NewDraggable );
  150.             end;
  151.         end; {TestNil}
  152. begin
  153.     GetPort( oldPort );
  154.     SetPort( offPort );
  155.     dragStuff := DragHandle( NewHandle( sizeOf( dragRecord )));
  156.     if dragStuff = nil then 
  157.     begin
  158.         NewDraggable := false;
  159.         SetPort( oldPort );
  160.         exit( NewDraggable );
  161.     end;
  162.  
  163. MoveHHi( Handle( dragStuff ));
  164. HLock( Handle( dragStuff ) );
  165. with dragStuff^^ do begin
  166. {try to allocate and erase the following bitmaps
  167.     - pictureBits holds the bitmap to display
  168.     - shadowBits holds the shadow
  169.     - underBits holds the bits obscured by the picture
  170.     - underShadowBits holds the bits obscured by the shadow
  171.     - offScreenBits holds the entire screen's image
  172. }
  173. {create a bitmap for the picture the size of the picture frame}
  174.     tempBounds := thePicture^^.picFrame;
  175.     if userPicBits <> nil 
  176.     then pictureBits := BitMap(userPicBits^)
  177.     else TestNil ( NewBitMap( pictureBits, tempBounds ) );
  178. {now create the drop shadow bitmap}
  179.     if userShadowBits <> nil
  180.     then shadowBits := BitMap(userShadowBits^)
  181.     else TestNil ( NewBitMap( shadowBits, tempBounds ) );
  182. {home tempBounds before setting up underBits}
  183.     with tempBounds do OffSetRect( tempBounds, -left, -top );
  184.     TestNil ( NewBitMap( underBits, tempBounds ) );
  185. {make the under-the-shadow bitmap the same size as the other underBits}
  186.     TestNil ( NewBitMap( underShadowBits, tempBounds ) );
  187. {clear out the bitmap for the picture}
  188.     SetPortBits( pictureBits );
  189.     EraseRect( pictureBits.bounds );
  190.     
  191. {make a region for the drop-shadow}
  192.     shadowRegion := NewRgn;
  193.     TestNil ( pointer( shadowRegion ));    
  194. {draw the picture into pictureBits & create thePictureRgn}
  195.     thePictureRgn := NewRgn;
  196.     TestNil ( pointer( thePictureRgn ));
  197.     OpenRgn;
  198.         HLock( Handle( thePicture ));
  199.             DrawPicture( thePicture, thePicture^^.picFrame );
  200.         HUnlock( Handle( thePicture ));
  201.     CloseRgn( thePictureRgn );
  202.     if EmptyRgn( thePictureRgn ) 
  203.         then RectRgn( thePictureRgn, thePicture^^.picFrame );
  204. {put the picture in pictureBits}
  205.     SetPortBits( pictureBits );
  206.     HLock( Handle( thePicture ));
  207.         DrawPicture( thePicture, thePicture^^.picFrame );
  208.     HUnlock( Handle( thePicture ));
  209.  
  210. {clear out shadowBits}
  211.     SetPortBits( shadowBits );
  212.     EraseRect( shadowBits.bounds );
  213. {fill in the shadow}
  214.     CopyRgn( thePictureRgn, shadowRegion );
  215.     PenMode( PatCopy );
  216.     PenPat( shadowStuff.thePattern );
  217.     PaintRgn( shadowRegion );
  218.     OffSetRgn( shadowRegion, shadowStuff.dx, shadowStuff.dy );
  219.     
  220. {the bounding rect surrounding the picture in position}
  221.     dragRect := pictureBits.bounds;
  222.     
  223.     SetRect( lastRect, 0,0,0,0 );
  224. end; {with dragStuff^^}
  225. HUnlock( Handle( dragStuff ) );
  226. NewDraggable := true;
  227. SetPort( oldPort );
  228. end; {InitDrag}
  229.  
  230. procedure DragItTo ( dragStuff: DragHandle; mousePt: point; 
  231.                                 centered : boolean );
  232. begin
  233. {we'll do all our work in the window manager port}
  234.     GetPort( oldPort );
  235.     SetPort( offPort );
  236.  
  237. MoveHHi( Handle( dragStuff ) );
  238. HLock( Handle( dragStuff ) );
  239. with dragStuff^^ do begin
  240.         otherMousePt := mousePt;
  241.     {home the region, the rect and the shadow region}
  242.         OffSetRgn( thePictureRgn, -dragRect.left, -dragRect.top );
  243.         OffSetRgn( shadowRegion, -dragRect.left, -dragRect.top );
  244.         OffSetRect( dragRect, -dragRect.left, -dragRect.top );
  245.     {center the object over the cursor}
  246.     {calculate mousePt here because we know the rect is home'd}
  247.         if centered then
  248.         begin
  249.             mousePt.h := mousePt.h - dragRect.right div 2;
  250.             mousePt.v := mousePt.v - dragRect.bottom div 2;
  251.         end;
  252.         OffSetRect( dragRect, mousePt.h, mousePt.v );
  253.         OffSetRgn( thePictureRgn, mousePt.h, mousePt.v );
  254.         OffSetRgn( shadowRegion, mousePt.h, mousePt.v );
  255.  
  256. {save bits underneath the shadow and then the bits under the picture}
  257.     if shadowStuff.visible
  258.     then begin
  259.     {work with the rectangle around the shadow}
  260.         with shadowStuff do OffsetRect( dragRect, dx, dy );
  261.     {remove any part of dragRect which is off the screen (clip it)}
  262.         if SectRect( screenBits.bounds, dragRect, updateRect ) then {};
  263.     {the destination rectangle will be home'd}
  264.         otherUpdateRect := updateRect;
  265.         with otherUpdateRect do OffSetRect( otherUpdateRect, -left, -top );
  266.     {take the snapshot}
  267.         CopyBits( offScreenBits, underShadowBits, updateRect, otherUpdateRect, 
  268.                 srcCopy,nil );
  269.     {move dragRect back over the picture area}
  270.         with shadowStuff do OffsetRect( dragRect, -dx, -dy );
  271.     end; {only if visible}
  272.     
  273.     {clip dragRect to inside the screen}
  274.         if SectRect( screenBits.bounds, dragRect, updateRect ) then {};
  275.     {home the destination rect}
  276.         otherUpdateRect := updateRect;
  277.         with otherUpdateRect do OffSetRect( otherUpdateRect, -left, -top );
  278.     {say “cheese”}
  279.         CopyBits( offScreenBits, underBits, updateRect, otherUpdateRect, 
  280.                 srcCopy,nil );
  281.  
  282.     {draw my object's shadow.  
  283.      => modification point <= if the copyMode is srcCopy you should
  284.      use shadowRegion to mask instead of nil.}    
  285.      if shadowStuff.visible
  286.      then begin
  287.         with shadowStuff do OffsetRect( dragRect, dx, dy );
  288.         CopyBits( shadowBits, offScreenBits, shadowBits.bounds, dragRect,
  289.                 shadowStuff.copyMode, nil );
  290.         with shadowStuff do OffsetRect( dragRect, -dx, -dy );
  291.     end; {only if visible}
  292.     
  293.     {draw my object}        
  294.         CopyBits( pictureBits, offScreenBits, pictureBits.bounds, dragRect,
  295.                 srcCopy, thePictureRgn );
  296.  
  297.     {update what was on there plus the new position for the object}
  298.         UnionRect( dragRect, lastRect, updateRect );
  299.     {include the shadow's rectangle}
  300.     if shadowStuff.visible
  301.     then begin
  302.         with shadowStuff do OffsetRect( dragRect, dx, dy );
  303.         UnionRect( dragRect, updateRect, updateRect );
  304.         with shadowStuff do OffsetRect( dragRect, -dx, -dy );
  305.     end; {only if visible}
  306.     {clip it all to the screen boundaries}
  307.         if SectRect( screenBits.bounds, updateRect, updateRect ) then {};
  308.         RectRgn( updateRegion, updateRect );
  309.     {wait for just the right moment}
  310.     {i can't see an improvement, can you?}
  311. {        synchCount := TickCount;
  312.         repeat until TickCount <> synchCount;
  313. }    {put it on the screen}
  314.         CopyBits( offScreenBits, screenBits, updateRect, updateRect,
  315.                 srcCopy, nil );
  316.     {restore bits underneath the picture}
  317.         {remove any part of dragRect which is off the screen}
  318.         if SectRect( dragRect, screenBits.bounds, updateRect ) then {};
  319.     {use a home'd rectangle for underBits}
  320.         otherUpdateRect := updateRect;
  321.         with otherUpdateRect do OffSetRect( otherUpdateRect, -left, -top );
  322.         CopyBits( underBits, offScreenBits, 
  323.                     otherUpdateRect, updateRect, srcCopy, nil );
  324.     {remember what parts of screenBits need to be fixed for next time}
  325.         lastRect := dragRect;
  326.     {restore bits underneath the shadow}
  327.     if shadowStuff.visible
  328.     then begin
  329.         with shadowStuff do OffsetRect( dragRect, dx, dy );
  330.     {clip it}
  331.         if SectRect( dragRect, screenBits.bounds, updateRect ) then {};
  332.     {home it}
  333.         otherUpdateRect := updateRect;
  334.         with otherUpdateRect do OffSetRect( otherUpdateRect, -left, -top );
  335.     {shoot it}
  336.         CopyBits( underShadowBits, offScreenBits, 
  337.                     otherUpdateRect, updateRect, srcCopy, nil );
  338.     {add to parts of screenBits to be fixed for next time}
  339.         UnionRect( lastRect, dragRect, lastRect );
  340.         with shadowStuff do OffsetRect( dragRect, -dx, -dy );
  341.     end;{only if shadow visible}
  342.     
  343. end; {with dragStuff^^}
  344. HUnlock( Handle( dragStuff ));
  345. SetPort( oldPort );
  346. end; {DragItTo}
  347.  
  348. procedure DisposeDraggable( dragStuff : DragHandle );
  349. begin {tidy up}
  350. if dragStuff <> nil then begin
  351.     HLock( Handle( dragStuff ) );
  352.     with dragStuff^^ do
  353.     begin
  354.         if pictureBits.baseAddr <> nil 
  355.             then DisposPtr( pictureBits.baseAddr );
  356.         if underBits.baseAddr <> nil 
  357.             then DisposPtr( underBits.baseAddr );
  358.         if underShadowBits.baseAddr <> nil 
  359.             then DisposPtr( underShadowBits.baseAddr );
  360.         if shadowBits.baseAddr <> nil 
  361.             then DisposPtr( shadowBits.baseAddr );
  362.         if offScreenBits.baseAddr <> nil 
  363.             then CopyBits( offScreenBits, screenBits, 
  364.                 offScreenBits.bounds, screenBits.bounds,
  365.                 srcCopy, nil );
  366.         if thePictureRgn <> nil 
  367.             then DisposHandle( Handle(thePictureRgn) );
  368.         if shadowRegion <> nil 
  369.             then DisposHandle( Handle(shadowRegion) );
  370.     end; {with dragStuff}
  371.     HUnlock ( Handle( dragStuff ) );
  372.     DisposHandle( Handle( dragStuff ) );
  373. end; {dragStuff <> nil}
  374. end; {DisposeDraggable}
  375.  
  376. procedure UpdateOffScreen (    dragStuff : DragHandle; 
  377.                                             Procedure drawProc );
  378. begin
  379.     GetPort( oldPort );
  380.     SetPort( offPort );
  381.     SetPortBits( offScreenBits );
  382.     drawProc;
  383.     SetPort( oldPort );
  384. end; {UpdateOffScreen}
  385.  
  386. procedure CloseDrag ( disposeBitMap : boolean );
  387. begin
  388.     if offPort <> nil then
  389.     begin
  390.         ClosePort( offPort );
  391.         DisposPtr( Pointer(offPort) );
  392.     end;
  393.     if updateRegion <> nil 
  394.         then DisposHandle( Handle(updateRegion) );
  395.     if disposeBitMap then
  396.         if offscreenBits.baseAddr <> nil
  397.         then DisposPtr( offScreenBits.baseAddr );
  398. end;{CloseDrag}
  399.  
  400. END. {unit Drag}